home *** CD-ROM | disk | FTP | other *** search
- # PSPScriptParse.py... This file does the parsing for the script editor.
- #
-
- import sys, re, string
- import PSPScriptMsgs
- import PSPScriptPyBlocks
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- #
- # this section contains the re pattern matching statements...
- #
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- PattImportPSP = re.compile(r"\bfrom\s*PSPApp\s*import\s*\*")
- PattImportJasc = re.compile(r"\bfrom\s*JascApp\s*import\s*\*")
- PattImportGeneral = re.compile(r"\bfrom\s*\w*\s*import\s*\*")
- PattDefDo = re.compile(r"\bdef\s*Do\(Environment\)\:")
- PattScriptProp = re.compile(r"\bdef\s*ScriptProperties\(\)\:\s*")
- PattScriptPropLine2 = re.compile(r"\s*\breturn\s*{\s*")
- PattBlankLine = re.compile(r"\s*\n")
- PattCommentLine = re.compile(r"\s*#")
- PattCloseParen = re.compile(r"\s*\)")
- PattDocBlock = re.compile(r"\s*'''")
- PattCloseBracket = re.compile(r"\s*\}")
- PattBlankCmtLine = re.compile("\s*#\s*\n")
- PattCloseBracketCmtLine = re.compile("\s*#\s*}\)")
- # match PSPCommand.
- # group(0) -> entire string
- # group(1) -> App.do(
- # group(2) -> quoted PSP Command Name
- # group(3) -> {
- PattPSPCmd = re.compile(r"(\s*App\.Do\(\s*Environment,\s*)" +
- r"(\'[\w*\s]+\')+\," +
- r"(\s*{\s*)")
- PattCR = re.compile(r"\s*\n")
- PattBracketParen = re.compile(r"\s*}\)")
-
- # match simple PSP parameter. Match through the ':'
- # group(1) -> parameter name
- # PattPSPParmSimple = re.compile(r"(\s*\'\s??\w*\s??\w*\')+\s*:\s*")
- '''
- PattPSPParmSimple = re.compile(r"(\s*\')" +
- r"(\s??\w*\s??\w*)" +
- r"\'+\s*:\s*")
- '''
-
- PattPSPParmSimple = re.compile(r"(\s*\')" +
- r"([\w*\s]+)" +
- r"\'+\s*:\s*")
-
- # match PSP parameter Start Dictionary. Find parm name and match
- # up through the opening brace
- # group(1) -> parameter name
- PattPSPParmStrDict = re.compile(r"(\s*\'\w*\')+\s*:\s*{")
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript
- # Author: Carl Lestor
- # Purpose: This class handles the parsing of the python script file. Its main job
- # is to parse the file and build up 'pyBlocks'. These objects represent blocks
- # of python code, psp commands, script descriptions and the like.
- # Returns: none
- # Parameters: fp - file handle for the file to parse.
- # pyBlockPtr = place to store the python blocks parsed
- # Notes: Errors are sent to std out; the script output window.
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- class ParseScript:
- def __init__(self):
- self.pyBlocks = [] # a place to pack hold the python blocks representing the script
- self.fp = 0 # handle of the file
- self.line = "" # line being parsed
- self.block = "" # blocks of code built up during parse
- self.linepos = 0 # line position during parse
- #print 'IN PARSE SCRIPT'
-
- # following data is used for understanding parse failures
- self.prevLine = "" # previous line
- self.prevPrevLine = "" # previous previous line
- self.lineNum = 0 # current line being parsed
- self.errorString = "" # set when a parse fails
- self.filename = "" # store the file name in case we need to invoke a text editor
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::openFile
- # Author: Steve Neumeyer
- # Purpose: initialize the file pointer for reading
- # Returns: none
- # Parameters: name - the filename to open
- # Notes: Simply opens the file and stores the reference in the file member
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def openFile(self, name):
- try:
- self.filename = name
- self.fp = open(name, 'r')
- return 1
- except:
- return 0
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::getLine
- # Author: Carl Lestor
- # Purpose: get a new line of text from the file
- # Returns: none
- # Parameters: cmtflag - indicates if we are handling a commented psp command
- # Notes: Much of the parsing shares the logic if we are parsing a commented psp
- # command or a non-commented one; hence the input flag. This method
- # silently skips the splat if we are doing comments.
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def getLine(self, cmtFlag):
- # if requested, handle comment lines by moving the line position past the opening comment char
- self.prevPrevLine = self.prevLine # save prev lines for diagnosis...
- self.prevLine = self.line
- self.line = self.fp.readline()
- self.linepos = 0
- self.lineNum = self.lineNum + 1
- if cmtFlag:
- # caller indicated we are in a state parsing commented material. skip over the comment
- # portion of the line. Return 0 if we do not find a comment....
- match = PattCommentLine.match(self.line)
- if match:
- self.linepos = match.end(0)
- return (self.line)
- else:
- return 0
- else:
- return (self.line)
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::addPyBlock
- # Author: Carl Lestor
- # Purpose: get a new line of text from the file
- # Returns: none
- # Parameters: type - type of block to add.
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def addPyBlock(self, type):
- # set up the block that was found.
- pyb = PSPScriptPyBlocks.PyBlock(type, self.block)
- self.pyBlocks = self.pyBlocks + [pyb]
- self.block = ""
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::parseFail
- # Author: Carl Lestor
- # Purpose: simply a place to handle parse errors consistently.
- # Returns: none
- # Parameters: error. String describing the type of error ecountered. Abstracted to
- # a unique file for translation ease.
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def parseFail(self, error):
- # the parse failed...
- ## print 'In parseFail, error = %s' % error
- self.errorString = PSPScriptMsgs.PSPSEmsgs(error)
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::getNextNonEscapedQuoteOld
- # Author: Steve Neumeyer
- # Purpose: get the next quote that is not escaped with a \ preceeding it
- # Returns: the position of the next non-escaped quote mark
- # -1 for error condition
- # Parameters: currentPosition - the current position in the string
- # string - the line of text being searched
- # Notes: this could be moved to PSPTools
- # this version only handles single quote marks '
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def getNextNonEscapedQuoteOld(self, currentPosition, str):
- escapedQuote = "\\'"
-
- while 1:
- nextQuotePos = string.find(str, "'", currentPosition)
- nextEscapedQuotePos = string.find(str, escapedQuote, currentPosition)
- if nextEscapedQuotePos != -1:
- nextEscapedQuotePos += 1
-
- # if the next quote is escaped, search forward from that position until
- # we find a non-escaped quote
- if nextQuotePos == nextEscapedQuotePos:
- currentPosition = 1+nextQuotePos # now we are searching from the last found quote pos
- continue
- else:
- return nextQuotePos
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::getNextNonEscapedQuote
- # Author: Steve Neumeyer
- # Purpose: get the next quote mark ' or " that is not escaped with a \ preceeding it
- # Returns: the position of the next non-escaped quote mark
- # -1 for error condition
- # Parameters: currentPosition - the current position in the string
- # string - the line of text being searched
- # doublequote - 1 or nonzero - we are dealing with a double quote
- # - 0 - single quote
- # Notes: updated version to handle ' and " quotes
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def getNextNonEscapedQuote(self, currentPosition, str, doublequote):
- if doublequote:
- escapedQuote = r'\"'
- else:
- escapedQuote = r"\'"
-
- while 1:
- if doublequote:
- nextQuotePos = string.find(str, '"', currentPosition)
- else:
- nextQuotePos = string.find(str, "'", currentPosition)
-
-
- nextEscapedQuotePos = string.find(str, escapedQuote, currentPosition)
- if nextEscapedQuotePos != -1:
- nextEscapedQuotePos += 1
-
- # if the next quote is escaped, search forward from that position until
- # we find a non-escaped quote
- if nextQuotePos == nextEscapedQuotePos:
- currentPosition = 1+nextQuotePos # now we are searching from the last found quote pos
- continue
- else:
- return nextQuotePos
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::EatValue
- # Author: Carl Lestor
- # Purpose: eats the value portion of a dictionary
- # entry. We simply consume all characters until the
- # comma indicating the value has ended. We must ignore
- # commas embedded in tuples, dicts, and lists.... When
- # successful, we add the value to the codeblock.
- # Returns: success - 1 if good, 0 if parse fails
- # moreLeft - 1 if true, 0 if end of dictionary
- # Value - value parsed
- # Parameters: cmtFlag - indicates if we are parsing a comment.
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def EatValue(self, cmtFlag):
-
- startoff = self.linepos
- fragToAdd = self.line[startoff:len(self.line)]
- Value = ''
-
- embedded = 0
- stringEating = 0
- skipNextStrQuotePos = 0
- blobEating = 0
- if self.line[self.linepos] == "'":
- doubleQuote = 0
- elif self.line[self.linepos] == '"':
- doubleQuote = 1
- else:
- doubleQuote = 0
-
- # store the position of the final quote mark in a string
- # this is an index to the last ' or " in a string, depending
- # on what type of quote we started with. default index is
- # the position of the last ' mark
- #finalQuotePos = string.rfind(self.line, "'")
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos+1, self.line, doubleQuote)
- while 1:
- # get the character and process it....
- ch = self.line[self.linepos]
-
- if blobEating:
- # Blobs start and end with triple single quotes - everything else is part of the value
- if ch == '\0' or ch == '\n':
- # New Line in BLOB
- Value = Value + fragToAdd[0:self.linepos + 1 - startoff]
- self.getLine(cmtFlag)
- if not self.line:
- # we hit eof in error. incomplete blob
- self.block = self.block + Value
- return (0, 0, Value)
- fragToAdd = self.line
- self.linepos = 0
- startoff = self.linepos
- elif ch =="\'":
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos+1, self.line, 0)
- self.linepos = self.linepos + 1
- if nextQuotePos == self.linepos and self.linepos + 1 == self.getNextNonEscapedQuote(self.linepos+1, self.line, 0):
- # Three quotes in a row - End of the blob
- self.linepos = self.linepos + 2
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos, self.line, 0)
- blobEating = 0
- else:
- self.linepos = self.linepos + 1
- elif stringEating:
- # handle strings... end chars in strings must be ignored...
- if ch == '\0' or ch == '\n':
- # New Line in String
- Value = Value + fragToAdd[0:self.linepos - 2 - startoff]
- self.getLine(cmtFlag)
- if not self.line:
- # we hit eof in error. incomplete string
- self.block = self.block + Value
- return (0, 0, Value)
- self.linepos = 0
- skipNextStrQuotePos = 1
- elif skipNextStrQuotePos and (ch == "\'" or ch == "\""):
- skipNextStrQuotePos = 0
- startoff = self.linepos + 1
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos+1, self.line, not singleQuote)
- fragToAdd = self.line[startoff:len(self.line)]
- elif singleQuote and ch == "\'" and self.linepos == nextQuotePos: #finalQuotePos:
- stringEating = 0
- singleQuote = 0
- elif not singleQuote and ch == '\"' and self.linepos == nextQuotePos: #finalQuotePos:
- stringEating = 0
- self.linepos = self.linepos + 1
- elif ch =="\'":
- stringEating = 1
- singleQuote = 1
- #finalQuotePos = string.rfind(self.line, "'")
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos+1, self.line, 0)
- self.linepos = self.linepos + 1
- if nextQuotePos == self.linepos and self.linepos + 1 == self.getNextNonEscapedQuote(self.linepos+1, self.line, 0):
- # Three quotes in a row - Start of a blob
- self.linepos = self.linepos + 2
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos, self.line, 0)
- stringEating = 0
- singleQuote = 0
- blobEating = 1
- elif ch =='\"':
- stringEating = 1
- singleQuote = 0
- #finalQuotePos = string.rfind(self.line, '"')
- nextQuotePos = self.getNextNonEscapedQuote(self.linepos+1, self.line, 1)
- self.linepos = self.linepos + 1
- # check for ending characters
- elif ch =="," and embedded == 0:
- # end of value, more dictionary to handle....
- Value = Value + fragToAdd[0:self.linepos - startoff]
- self.block = self.block + Value + ch
- self.linepos = self.linepos + 1
- self.chkEOLN(cmtFlag)
- return (1, 1, Value)
- elif ch == "}" and embedded == 0:
- # end of value, end of dictionary....
- Value = Value + fragToAdd[0:self.linepos - startoff]
- self.block = self.block + Value + ch
- self.linepos = self.linepos + 1
- self.chkEOLN(cmtFlag)
- return (1, 0, Value)
-
- # handle being imbedded in dicts, tuples, or lists...
- elif (ch == '(' or ch =='{' or ch == '['):
- embedded = embedded + 1
- self.linepos = self.linepos + 1
- elif ch == ')' or ch =='}' or ch == ']':
- embedded = embedded - 1
- self.linepos = self.linepos + 1
-
- # go right through EOLN for longer parms...
- elif ch == '\0' or ch == '\n':
- # we hit end of line
- Value = Value + fragToAdd[0:self.linepos + 1 - startoff]
- self.getLine(cmtFlag)
- if not self.line:
- # we hit eof in error. incomplete dict or imbalanced parens
- self.block = self.block + Value
- return (0, 0, Value)
- fragToAdd = self.line
- self.linepos = 0
- startoff = self.linepos
- else:
- # any old character
- self.linepos = self.linepos + 1
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::EatDocBlock
- # Author: Carl Lestor
- # Purpose: eats the contents of a triple quoted documentation block
- # The first triple quoted chars have been found.. When
- # successful, we add the value to the codeblock.
- # Returns: success - 1 if good, 0 if parse failure
- # Parameters: none
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def eatDocBlock(self):
-
- startoff = self.linepos
- fragToAdd = self.line[startoff:len(self.line)]
- singleQuoteDepth = 0
-
- while singleQuoteDepth < 3:
- ch = self.line[self.linepos]
- self.linepos = self.linepos + 1
-
- if ch == "\'":
- singleQuoteDepth = singleQuoteDepth + 1
-
- # handle multi line doc blocks...
- elif ch == '\0' or ch == '\n':
- # we hit end of line
- self.block = self.block + fragToAdd[0:self.linepos + 1 - startoff]
- self.getLine(0)
- if not self.line:
- # we hit eof in error. incomplete doc block.
- return (0)
- fragToAdd = self.line
- self.linepos = 0
- startoff = 0
- singleQuoteDepth = 0
- else:
- # any old character
- singleQuoteDepth = 0
-
- # end of doc block found....
- self.block = self.block + fragToAdd[0:self.linepos + 1 - startoff]
- self.chkEOLN(0)
- return (1)
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::EatDocBlock
- # Author: Carl Lestor
- # Purpose: check for end of line. consume white space as we go...
- # Returns:
- # Parameters: chkCmtFlag - indicates if we are parsing a comment or not.
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def chkEOLN(self, chkCmtFlag):
-
- while 1:
- ch = self.line[self.linepos]
- if ch == " " or ch == "\n":
- # consume it
- self.linepos = self.linepos + 1
- self.block = self.block + ch
- if self.linepos == len(self.line):
- # we have reached the end of line.
- self.getLine(chkCmtFlag)
- if (chkCmtFlag):
- # we found a new commented line. need to pick up the splat...
- self.block = self.block + self.line[0:self.linepos]
- return (1)
- else:
- return (1)
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::ParseDictionary
- # Author: Carl Lestor
- # Purpose: parse a dictionary.
- # Returns: success - 1 if good, 0 if parse failure
- # Parameters: OurParms - dictionary or parms being built.
- # cmtFlag - indicates if we are parsing a comment or not.
- # Notes: Finds a dictionary entry and adds it to OurParms
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def parseDictionary(self, OurParms, cmtFlag):
-
- # assumes open brace has been consumed. match all
- # and consume the end brace.
- while 1:
- # we either have consumed the line with the re match or there are some
- # parms also on that line. if at the end, get a new one....
- if self.linepos >= len(self.line):
- self.getLine(cmtFlag)
- if not self.line:
- return 0
- if (cmtFlag):
- # we found a new commented line. need to pick up the splat...
- self.block = self.block + self.line[0:self.linepos]
- # find a parmName:value pair. first the name.
- match = PattPSPParmSimple.match(self.line, self.linepos)
- if match:
- # parmName found. update block and get value.
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- self.chkEOLN(cmtFlag)
- ok, moreLeft, Value = self.EatValue(cmtFlag)
- if not ok:
- return 0
-
- # need to trim the spaces from match group1
- OurParms.append([match.group(2), Value])
- if not moreLeft:
- return 1
- else:
- return 0
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::checkState
- # Author: Carl Lestor
- # Purpose: checks to see if the statement found is valid in the current state
- # Returns:
- # Parameters: state - current state of the parse
- # StatementFound - indicates what type of statement was discovered.
- # Notes: The purpose of this method is to provide the user with a more meaningful
- # error msg if the script obviously will not run. Hopefully this will aid users
- # new to hand editing scripts. When they invoke the Script Editor, some simple
- # error will be discovered. This is light and not thorough syntax checking.
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def checkState(self, state, StatementFound):
-
- #
- # state tables. for each state, the dictionary contains the pair of 'received statement type' and
- # 'new state'. If the new type contains 'ERROR:' in it. the parse failed. Error message text
- # is isloated in PSPScriptMsgs for translation....
- #
- ExpectImport = {"Import":"DefDo",
- "Comment":"Import",
- "Script":"ERROR:Parse11",
- "CmtPSPCmd":"ERROR:Parse12",
- "DefDo":"ERROR:Parse13",
- "PSPCmd":"ERROR:Parse14"}
-
- ExpectDefDo = {"Import":"ERROR:Parse21",
- "Comment":"DefDo",
- "Script":"DefDo",
- "CmtPSPCmd":"ERROR:Parse22",
- "DefDo":"PSPCmd",
- "PSPCmd":"ERROR:Parse23"}
-
- ExpectPSPCmd = {"Import":"ERROR:Parse31",
- "Comment":"PSPCmd",
- "Script":"PSPCmd",
- "CmtPSPCmd":"PSPCmd",
- "DefDo":"ERROR:Parse32",
- "PSPCmd":"PSPCmd"}
-
- if state == "Import":
- newstate = ExpectImport[StatementFound]
- elif state == "DefDo":
- newstate = ExpectDefDo[StatementFound]
- else:
- newstate = ExpectPSPCmd[StatementFound]
-
- if newstate.count("ERROR"):
- return (0, newstate)
- else:
- return (1, newstate)
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Class: ParseScript::parseScript
- # Author: Carl Lestor
- # Purpose: This is the main method that parses the script.
- # Returns:
- # success - 1 if good, 0 if bad
- # PSPCmdCount - number of psp commands found
- # Parameters: none
- # Notes: The method is a basic loop processing a line at a time of the input file. Top
- # level line recognition is done with re pattern matching. Outer loop looks for
- # basic types of statements and then parses the details.
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def parseScript(self):
-
- PSPCmdCount = 0
- ExpectedStmt = "Import"
-
- while 1:
- self.getLine(0)
- if not self.line:
- return (1, PSPCmdCount)
- #
- # try to match our line to one of our patterns.... first the import statement
- #
- match = PattImportPSP.match(self.line)
- if match:
- parseOK, ExpectedStmt = self.checkState(ExpectedStmt, "Import")
- if not parseOK:
- self.parseFail(ExpectedStmt)
- return (0, PSPCmdCount)
- self.block = self.line
- self.addPyBlock ("ImportPSP")
- continue
- match = PattImportJasc.match(self.line)
- if match:
- parseOK, ExpectedStmt = self.checkState(ExpectedStmt, "Import")
- if not parseOK:
- self.parseFail(ExpectedStmt)
- return (0, PSPCmdCount)
- self.block = self.line
- self.addPyBlock ("ImportPSP")
- continue
- #
- # match a def do statement
- #
- match = PattDefDo.match(self.line)
- if match:
- parseOK, ExpectedStmt = self.checkState(ExpectedStmt, "DefDo")
- if not parseOK:
- self.parseFail(ExpectedStmt)
- return (0, PSPCmdCount)
- self.block = self.line
- self.addPyBlock ("DefDo Match")
- continue
- #
- # match the script properties
- #
- match = PattScriptProp.match(self.line)
- if match:
- parseOK, ExpectedStmt = self.checkState(ExpectedStmt, "Script")
- if not parseOK:
- self.parseFail(ExpectedStmt)
- return (0, PSPCmdCount)
- self.block = self.line
- # line 1 matches. match line2.
- self.getLine(0)
- self.linepos = 0
- match = PattScriptPropLine2.match(self.line)
- if match:
- # self.block = self.line
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- parmList = []
- if self.parseDictionary(parmList, 0):
- self.addPyBlock ("Script Properties")
- # print "parmList = ", parmList # may not need parmList of dict items...
- else:
- # failed to parse script properties parameters
- self.parseFail("ERROR:Parse41")
- return (0, PSPCmdCount)
- else:
- # failed to parse script properties return statement
- self.parseFail("ERROR:Parse42")
- return (0, PSPCmdCount)
- #
- # match a psp command
- #
- match = PattPSPCmd.match(self.line)
- if match:
- parseOK, ExpectedStmt = self.checkState(ExpectedStmt, "PSPCmd")
- if not parseOK:
- self.parseFail(ExpectedStmt)
- return (0, PSPCmdCount)
- # set the end to the last match position. group 3....
- self.block = match.group(0)
- self.linepos = match.end(0)
- parmList = []
- if self.parseDictionary(parmList, 0):
- # we have parsed the dictionary. pick up the trailing paren
- match = PattCloseParen.match(self.line, self.linepos)
- if match:
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- self.addPyBlock ("PSPCmd")
- PSPCmdCount = PSPCmdCount + 1
- else:
- # need to handle the case of a command with no dict/repository
- # match = PattCloseBracket.match(self.line, self.linepos)
- match = PattCR.match(self.line, self.linepos)
- # the command has no dict/repository
- if match:
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- self.getLine(0)
- match = PattBracketParen.match(self.line, self.linepos)
- if match:
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- else: # error
- self.parseFail("ERROR:Parse51")
- return (0, PSPCmdCount)
- self.addPyBlock("PSPCmd")
- PSPCmdCount += 1
- else:
- # failed to parse psp command parameter dictionary
-
- # csl... this error msg is non optimal. mismatched parens can cause the parse
- # to go deep into the file. line shown in error obj could be far away from bad
- # parm list. (looking for ending paren down the file.) improvement to add pspcmd to
- # error msg....
-
- self.parseFail("ERROR:Parse51")
- return (0, PSPCmdCount)
- continue
-
- #
- # match a commented line or commented psp command
- #
- match = PattCommentLine.match(self.line)
- if match:
- self.linepos = match.end(0)
- if ExpectedStmt == "PSPCmd":
- # could be a commented psp command. better check for that. else just a cmt....
- self.block = self.block + match.group(0)
- keepLookingFrom = match.end(0)
- match = PattPSPCmd.match(self.line, keepLookingFrom)
- if match:
- # we have found a comment that starts off like a psp command. check the parms.
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- parmList = []
- if self.parseDictionary(parmList, 1):
- # we have parsed the dictionary. pick up the trailing paren
- match = PattCloseParen.match(self.line, self.linepos)
- if match:
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- self.addPyBlock ("CmtedPSPCmd")
- PSPCmdCount = PSPCmdCount + 1
- continue
- else: # commented command with empty dict/repository (ex: UndoLastCmd)
- match = PattBlankCmtLine.match(self.line, 0)
- if match:
- self.block = self.block + match.group(0)[1:]
- self.linepos = match.end(0)
- self.getLine(1)
- match = PattCloseBracketCmtLine.match(self.line, 0)
- if match:
- self.block = self.block + match.group(0)
- self.linepos = match.end(0)
- self.addPyBlock("CmtedPSPCmd")
- PSPCmdCount += 1
- continue
- else:
- self.parseFail("ERROR:Parse51")
- return (0, PSPCmdCount)
- else:
- self.parseFail("ERROR:Parse51")
- return (0, PSPCmdCount)
- else:
- self.block = ''
-
- # csl.... there are several ways to fall through to this. UT all...
- # ended up being a typical comment
- # self.block = self.block + self.line[self.linepos:len(self.line)]
- self.block = self.block + self.line[0:len(self.line)]
- self.addPyBlock ("PythonCmt")
- continue
-
- #
- # match a doc block (python within a triple quoted block..)
- #
- match = PattDocBlock.match(self.line)
- if match:
- self.block = match.group(0)
- self.linepos = match.end(0)
- if self.eatDocBlock():
- self.addPyBlock ("DocBlock")
- else:
- # failed to find the end of doc block
- self.parseFail("ERROR:Parse52")
- return (0, PSPCmdCount)
- continue
-
- #
- # match a blank or new line. these are allowed anywhere...
- #
- match = PattBlankLine.match(self.line)
- if match:
- self.block = self.line
- self.addPyBlock ("BlankLine")
- continue
-
- else:
- #
- # everything else is a general python code block
- self.block = self.line
- self.addPyBlock ("PyCode")
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Function: DoParse
- # Author: Steve Neumeyer
- # Purpose: Do a parse and return the result
- # Returns: the result of the parse
- # Parameters: fname - file to parse
- # Notes:
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def DoParse(fname, sp):
-
- parseResult = 0
- if sp.openFile(fname):
- parseResult = sp.parseScript()
-
- return sp, parseResult
-
-
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- # Function: DriveParse
- # Author: Carl Lestor
- # Purpose: This is a utility function to test the parse.
- # Returns:
- # Parameters:
- # fname - file to parse
- # printIt - true if we should print to stdout the parse details in addition to logging to the file
- # Notes: This is not part of the production product. Drive UT from external script. Write basic results
- # to std out and details to output file name derived from input file name...
- # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- def DriveParse(fname, printIt, sp):
-
- # instance declared in calling function -- sp = ParseScript()
- printString = ""
- if sp.openFile(fname):
-
- # create output file name and set up for logging....
- nameParts = string.split(fname, '.')
- outName = nameParts[0] + "OUT.txt"
- outf = open(outName, 'w')
-
- parseResult = sp.parseScript()
-
- # print the summary result to stdout and the details to the output file....
- if parseResult:
- # parse was good
- print "filename:" + fname + " Parse Result:good"
- outf.write("filename:" + fname + " Parse Result:good\n\n\n")
- for pyblock in sp.pyBlocks:
- block, cmd = pyblock.dump()
- outf.write("Pyblock:" + cmd + "\n" + block + "\n")
- printString = printString + "Pyblock:" + cmd + "\n" + block + "\n"
- else:
- # parse failure
- print "filename:" + fname + " " + sp.errorString
- outf.write("filename:" + fname + " " + sp.errorString + "\n")
- outf.write(sp.prevPrevLine + sp.prevLine + sp.line)
- outf.write("Failing line number:" + str(sp.lineNum) + " Failing Char Position:" + str(sp.linepos))
- printString = printString + sp.prevPrevLine + sp.prevLine + sp.line
- printString = printString + "Failing line number:" + str(sp.lineNum) + " Failing Char Position:" + str(sp.linepos)
-
- if printIt == "dump":
- print printString
-
- outf.close()
-
- else:
- print "failed to open file:", fname
-
- return sp
-
- ######################
- if __name__ == '__main__':
-
- sp = ParseScript()
-
- DriveParse(fname, "dump", sp)
-
- ## if len(sys.argv) == 3:
- ## DriveParse(sys.argv[1], sys.argv[2])
- ## elif len(sys.argv) == 2:
- ## # assume no stdout dumping is wanted
- ## DriveParse(sys.argv[1], "NoDump")
- ## else:
- ## print "Needs 2 parameters: filename and dump option. Second parm = 'dump' to send details to stdout."
-